package com.gtp.mq.demo;

import java.io.IOException;

import org.junit.After;
import org.junit.Before;

import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ConfirmListener;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.ReturnListener;
import com.rabbitmq.client.ShutdownListener;
import com.rabbitmq.client.ShutdownSignalException;

/**
 * 主要的一些对象:
 * 	  ConnectionFactory
 * ->
 * 	  Connection
 * ->
 *    Channel 操作都在渠道上，线程非安全的
 *    
 * QA:为什么不直接使用Connection? 资源有限,Channel更高效
 */
public class BaseFactory {

	protected Connection conn;

	// 初始化连接
	@Before
	public void init() throws Exception {

		// Create a connection factory
		ConnectionFactory factory = new ConnectionFactory();

		// RabbitMQ Server broker
		factory.setHost(Constants.mq_host);
		factory.setPort(5672);
		factory.setUsername(Constants.mq_user);
		factory.setPassword(Constants.mq_pwd);

		// Virtual Host
		factory.setVirtualHost(Constants.mq_vhost);

		// getting a connection
		conn = factory.newConnection();
	}

	@After
	public void close() throws Exception {
		if (conn != null) {
			conn.close();
		}
	}

	/**
	 * 获得渠道:注意Channel不是线程安全的！切记！切记！
	 * 单个连接中创建多个channel，相对来说创建和销毁它们的代价要小的多
	 * 通道不是线程安全的(Channel不是线程安全的，在实际使用中，
	 * 应该通过Connection为每个线程创建独立的Channel)
	 */
	protected Channel getChannel() {
		try {
			// creating a channel
			if (conn == null) {
				return null;
			}
			
			Channel channel = conn.createChannel();
			
			//Listener使用
			channel.addConfirmListener(new ConfirmListener(){

				@Override
				public void handleAck(long deliveryTag, boolean multiple) throws IOException {
					System.out.println("ConfirmListener ack");
				}

				@Override
				public void handleNack(long deliveryTag, boolean multiple) throws IOException {
					System.out.println("ConfirmListener nack");
				}
				
			});
			
			//监听关闭:若未执行成功可获得状态
			channel.addShutdownListener(new ShutdownListener(){
				@Override
				public void shutdownCompleted(ShutdownSignalException cause) {
					System.out.println(cause);
				}
			});
			
			/*
			 * 在发布消息时设置mandatory等于true，监听消息是否有相匹配的队列
			 * ReturnListener，在发布消息时设置mandatory等于true，监听消息是否有相匹配的队列，
			 * 没有时ReturnListener将执行handleReturn方法，消息将返给发送者 
			 * 设置mandatory=true，当路由不到队列时返回给消息发送者，在return监听器中接收 
			 * 设置immediate=true，当路由不到消费者时返回，3.0以后版本已废弃，
			 * 会影响镜像队列性能，建议采用消息TTL和DLX 
			 */
			channel.addReturnListener(new ReturnListener() {
					@Override
					public void handleReturn(int replyCode,
				            String replyText,
				            String exchange,
				            String routingKey,
							BasicProperties properties,
							byte[] body)
							throws IOException {
						System.out.println("########################");
						System.out.println("replyCode="+replyCode);
						System.out.println("replyText="+replyText);
						System.out.println("exchange="+exchange);
						System.out.println("routingKey="+routingKey);
						System.out.println("properties="+properties);
						System.out.println("body="+new String(body));
						System.out.println("没有相匹配的队列!");
					}
				});
			
			return channel;
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
}
